#include <iostream>
#include <fstream>
#include "pb_cfg_partner.pb.h"
#include "commclass.h"
#include "commmsg.h"
#include "../mainctrl.h"
#include "../card/CCardMgr.h"
#include "../data/CPlayerOnlineData.h"
#include "CPartnerMgr.h"
#include "CPartnerCfg.h"
#include "CUserPartner.h"
#include "MsgGM.pb.h"
#include "../skill/CSkill.h"
#include "CTSizeString.h"

int CPartnerMgr::LoadConfig(const char* szLogPath)
{
    int iRet = 0;
    if (szLogPath == NULL)
    {
        CT_ERROR(("Partner Config Path is null"));
        return RET_SYSTEM_FAIL;
    }

    iRet = _stPartnerCfg.Init();
    CT_RETURN(iRet);

    pb_cfg_partner stPartnerPBCfg;
    std::fstream stFileInput(szLogPath, std::ios::in | std::ios::binary);
    if (!stPartnerPBCfg.ParseFromIstream(&stFileInput))
    {
        CT_ERROR(("Failed to Parse PartnerCfg!"));
        return RET_SYSTEM_FAIL;
    }

    //解析配置文件内容
    SetRoleReputationLimit(0);

    CTaskID stTaskID;
    CTaskConfigData stTaskConfigData;

    CConditionData stConPair;
    CPartnerCfgData stCfgData;
    CT_TRACE(("Partner Config Count(%d)", stPartnerPBCfg.partner_cfg_rows_size()));
    for (int i = 0; i < stPartnerPBCfg.partner_cfg_rows_size(); ++i)
    {
        const pb_cfg_partner_pb_cfg_partner_cfg_unit& stPartnerPBCfgUnit
            = stPartnerPBCfg.partner_cfg_rows(i);

        stCfgData.Clear();

        stCfgData._bIsMan = stPartnerPBCfgUnit.is_man() ? true : false;
        stCfgData._chCareer = stPartnerPBCfgUnit.career();
        stCfgData._shResID = stPartnerPBCfgUnit.res_id();
        stCfgData._iRepu = stPartnerPBCfgUnit.repu();
        stCfgData._iSilver = stPartnerPBCfgUnit.silver();
        stCfgData._iVit = stPartnerPBCfgUnit.base_vit();
        stCfgData._iStr = stPartnerPBCfgUnit.base_str();
        stCfgData._iInt = stPartnerPBCfgUnit.base_int();
        stCfgData._iAgi = stPartnerPBCfgUnit.base_agi();
        stCfgData._uiNormalSkiID = (unsigned int)stPartnerPBCfgUnit.normal_skill();
        stCfgData._uiMagicSkiID = (unsigned int)stPartnerPBCfgUnit.magic_skill();
        stCfgData._iSpeEffect = stPartnerPBCfgUnit.spe_id();
        stCfgData._iStatusGroupID = stPartnerPBCfgUnit.status_group();
        stCfgData._iSignBattle = stPartnerPBCfgUnit.sign_battle();
        stCfgData._iSignSilver = stPartnerPBCfgUnit.sign_silver();
        stCfgData._iSignVit = stPartnerPBCfgUnit.sign_vit();
        stCfgData._iSignStr = stPartnerPBCfgUnit.sign_str();
        stCfgData._iSignInt = stPartnerPBCfgUnit.sign_int();
        stCfgData._iSignAgi = stPartnerPBCfgUnit.sign_agi();
        stCfgData._iLockBattle = stPartnerPBCfgUnit.lock_battle();
        stCfgData._iLockEffect = stPartnerPBCfgUnit.lock_effect();
        stCfgData._iWeaponID = stPartnerPBCfgUnit.weapon_id();
        stCfgData._iJoinWay = stPartnerPBCfgUnit.join_way();
        stCfgData._iJoinArgu = stPartnerPBCfgUnit.join_argu();
        stCfgData._iJoinFrontID = stPartnerPBCfgUnit.front_join_id();

        stCfgData._stInitAttr._aiAttr[EXT_ATTR_HP] = stPartnerPBCfgUnit.hp();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_PHY_ATK] = stPartnerPBCfgUnit.phy_atk();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_PHY_DEF] = stPartnerPBCfgUnit.phy_def();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_MAG_ATK] = stPartnerPBCfgUnit.mag_atk();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_MAG_DEF] = stPartnerPBCfgUnit.mag_def();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_HIT] = stPartnerPBCfgUnit.hit();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_DODGE] = stPartnerPBCfgUnit.dodge();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_DOUBLE] = stPartnerPBCfgUnit.role_double();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_ANTI_DOUBLE] = stPartnerPBCfgUnit.anti_double();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_BLOCK] = stPartnerPBCfgUnit.block();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_ANTI_BLOCK] = stPartnerPBCfgUnit.anti_block();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_TURN_ORDRE] = stPartnerPBCfgUnit.order();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_CRIT] = stPartnerPBCfgUnit.crit();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_IMMUNE_INJURY] = stPartnerPBCfgUnit.immune_injury();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_REACT_INJURY] = stPartnerPBCfgUnit.react_injury();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_PENETRATE] = stPartnerPBCfgUnit.penetrate();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_TREATMENT] = stPartnerPBCfgUnit.treatment();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_FIGHT_BACK] = stPartnerPBCfgUnit.fight_back();
        stCfgData._stInitAttr._aiAttr[EXT_ATTR_ACT_ANGER] = stPartnerPBCfgUnit.act_anger();

        if (!stCfgData.IsValidJoinWay())
        {
            return ERROR_PARTNER_UNKNOW_JOIN_WAY;
        }

        if (stCfgData.IsAboutTaskJoinWay() && stCfgData._iJoinArgu > 0 &&
                stCfgData._iJoinFrontID > 0)
        {
            CMainCtrl::m_pstMain->m_stTaskMgr.GetTaskIDStruct(
                stCfgData._iJoinArgu, stTaskID);
            iRet = CMainCtrl::m_pstMain->m_stTaskMgr.GetTaskConfig(stTaskID,
                stTaskConfigData);
            CT_RETURN(iRet);

            stConPair._iKey = stCfgData._iJoinWay;
            stConPair._iValue = stCfgData._iJoinFrontID;
            stConPair._iArgument = stCfgData._iJoinArgu;
            _stPartnerCfg.AddCondition(stConPair);
        }

        iRet = CMainCtrl::m_pstMain->m_stRoleMgr.CheckValidCareer(
            stCfgData._chCareer);
        CT_RETURN(iRet);

        iRet = CMainCtrl::m_pstMain->m_stSkillMgr.IsValidSkill(
            stCfgData._uiNormalSkiID, CSkill::SKILL_TYPE_NORMAL);
        CT_RETURN(iRet);

        iRet = CMainCtrl::m_pstMain->m_stSkillMgr.IsValidSkill(
            stCfgData._uiMagicSkiID, CSkill::SKILL_TYPE_MAGIC);
        CT_RETURN(iRet);

        iRet = CMainCtrl::m_pstMain->m_stStatusMgr.IsValidStatusGroup(
            stCfgData._iStatusGroupID);
        CT_RETURN(iRet);

        iRet = AddPartnerCfg(stCfgData);
        CT_RETURN(iRet);
    }

    CT_TRACE(("Partner Reputation Count(%d)", stPartnerPBCfg.partner_cfg_repu_rows_size()));
    for (int i = 0; i < stPartnerPBCfg.partner_cfg_repu_rows_size(); ++i)
    {
        const pb_cfg_partner_pb_cfg_partner_cfg_repu_unit& stPBRepuUnit
            = stPartnerPBCfg.partner_cfg_repu_rows(i);
        if (GetRoleReputationLimit() < stPBRepuUnit.reputation())
        {
            SetRoleReputationLimit(stPBRepuUnit.reputation());
        }
    }

    return 0;
}

int CPartnerMgr::AddPartnerCfg(CPartnerCfgData& stCfgData)
{
    return _stPartnerCfg.AddConfig(stCfgData);
}

int CPartnerMgr::FindPartnerCfg(short shResID)
{
    return _stPartnerCfg.FindConfig(shResID);
}

CPartnerCfgData& CPartnerMgr::GetPartnerCfg(int iIndex)
{
    return _stPartnerCfg.GetConfig(iIndex);
}

int CPartnerMgr::GetPartnerCfg(short shResID, CPartnerCfgData& stCfgData)
{
    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgDataTmp = GetPartnerCfg(iIndex);

    stCfgData = stCfgDataTmp;

    return 0;
}

int CPartnerMgr::GetPartnerFighting(short shResID, CPlayerOnlineData& stPlayerOnline)
{
    int iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex >= 0)
    {
        CPartnerUnit& stPartnerUnit =
            stPlayerOnline._stUserPartner.GetPartner(iIndex);
        return stPartnerUnit.GetFighting();
    }

    return 0;
}

int CPartnerMgr::InitPartnerOnlineData(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    int iRet = 0;
    int iIndex = 0;
    stPlayerOnline._stUserPartner._astOnlineData.Clear();

    for (int i = 0; i < stPlayerDetail._stUserPartner._astActData.Size(); ++i)
    {
        iIndex = FindPartnerCfg(
            stPlayerDetail._stUserPartner._astActData[i]._shResID);
        if (iIndex < 0)
        {
            return ERROR_PARTNER_EMPTY_CFG;
        }
        CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

        CPartnerUnit stPartnerUnit;

        iRet = stPartnerUnit.InitByActData(stCfgData,
            stPlayerDetail._stUserPartner._astActData[i], stPlayerBase,
            stPlayerDetail, stPlayerOnline, stPlayerDetailEx1);
        CT_RETURN(iRet);

        iRet = stPlayerOnline._stUserPartner._astOnlineData.AddOneItem(
            stPartnerUnit);
        if (iRet < 0)
        {
            return iRet;
        }
    }

    return 0;
}

int CPartnerMgr::PartnerGetActCard(MsgAnsActPartner& stMsgActPartner,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfo& stPlayerDetailInfo, CPartnerUnit& stPartnerUnit)
{
    int iRet = 0;
    int iIndex = 0;

    iIndex = stPlayerDetailInfo._stUserPartner.FindActData(stPartnerUnit._shResID);
    if (iIndex < 0)
    {
        CT_WARNING(("no partner %d", stPartnerUnit._shResID));
        return 0;
    }
    CPartnerActData& stPartnerActData = stPlayerDetailInfo._stUserPartner.GetPartnerActData(iIndex);

    int iCanWareCardCount = stPartnerActData._stPlayerWareCard.CanWareCardCount(stPartnerActData._shLevel);
    stMsgActPartner.set_can_ware_card_count(iCanWareCardCount);
    for (int i = 0; i < iCanWareCardCount; ++i)
    {
        MsgGridItemInfo* pstCard = stMsgActPartner.add_cards();
        unsigned int uiCardID = 0;
        iRet = stPartnerActData._stPlayerWareCard.GetCardByPos(i, uiCardID);
        CHECK_RETURN(iRet);

        if (uiCardID == 0) //没有卡片
        {
            pstCard->set_item_store_pos(i);
            pstCard->set_item_config_id(0);
            pstCard->set_item_count(0);            
            pstCard->set_item_type(0);
        }
        else
        {
            CMainCtrl::m_pstMain->m_stCardMgr.GetCardInfo(stPlayerOnline._stUserCard,
                stPlayerDetailInfo, uiCardID, *pstCard);
        }
    }

    //获取卡片分数
    unsigned int uiCardPoint = 0;
    CMainCtrl::m_pstMain->m_stCardMgr.GetCardPoint(stPlayerOnline._stUserCard, stPartnerActData._stPlayerWareCard, uiCardPoint);
    stMsgActPartner.set_card_point(uiCardPoint);

    return 0;
}

int CPartnerMgr::CalcExtAttr(CPartnerCfgData& stCfgData,
        CPlayerAttr& stPartnerAttr, short shLevel, bool bCalcExtAttr)
{
    //先计算加成的基础属性
    stPartnerAttr += stCfgData._stInitAttr;

    stPartnerAttr._aiAttr[BASE_ATTR_INT] += stCfgData._iInt;
    stPartnerAttr._aiAttr[BASE_ATTR_VIT] += stCfgData._iVit;
    stPartnerAttr._aiAttr[BASE_ATTR_STR] += stCfgData._iStr;
    stPartnerAttr._aiAttr[BASE_ATTR_AGI] += stCfgData._iAgi;

    return CMainCtrl::m_pstMain->m_stRoleMgr.CalcCareerLevelAttr(stPartnerAttr,
        stCfgData.GetCareer(), shLevel, bCalcExtAttr);
}

int CPartnerMgr::CalcPartnerFavor(short shResID, int iFavor, int& iFavorRate)
{
    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    float fFavor = 0.0;
    if (iFavor <= 0)
    {
        iFavorRate = 0;
    }
    else if (iFavor < PARTNER_FAVOR_FOR_LOCK)
    {
        fFavor = (iFavor * 1.0 ) / stCfgData._iSignBattle;
        iFavorRate = (int)(fFavor * 1000);
    }
    else if (iFavor >= PARTNER_FAVOR_FOR_LOCK && iFavor < PARTNER_FAVOR_FOR_POWER)
    {
        fFavor = ((iFavor - PARTNER_FAVOR_FOR_LOCK) * 1.0 ) / stCfgData._iLockBattle;
        iFavorRate = (int)(fFavor * 1000) + PARTNER_FAVOR_FOR_LOCK;
    }
    else if (iFavor >= PARTNER_FAVOR_FOR_POWER)
    {
        iFavorRate = PARTNER_FAVOR_FOR_POWER;
    }

    return 0;
}

int CPartnerMgr::PartnerGetJoinWay(CPlayerBaseInfo& stPlayerBase,
        CPlayerOnlineData& stPlayerOnline, MsgAnsPartner& stAns)
{
    //知会前端当前主角具有的特殊招募条件
    if (stPlayerBase._stVipData._ucCanGetFirstPayBonus > 0)//首充招募条件
    {
        stAns.add_append_join_type(PARTNER_JOIN_WAY_FIRST_PAY);
    }

    //任务相关
    CTaskID stTaskID;
    for (int i = 0; i < _stPartnerCfg.GetConditionSize(); ++i)
    {
        CConditionData& stConPair = _stPartnerCfg.GetCondition(i);
        CMainCtrl::m_pstMain->m_stTaskMgr.GetTaskIDStruct(stConPair._iArgument,
            stTaskID);
        if (PARTNER_JOIN_WAY_RECEIVE_OR_FINISH_TASK == stConPair._iKey)//已接取或完成特定任务
        {
            if (CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskAccepted(
                    stPlayerOnline._stUserTask, stTaskID) ||
                CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskFinished(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                stAns.add_append_join_type(stConPair._iValue);
            }
        }
        else if (PARTNER_JOIN_WAY_RECEIVE_TASK == stConPair._iKey)//已接取特定任务
        {
            if (CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskAccepted(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                stAns.add_append_join_type(stConPair._iValue);
            }
        }
        else if (PARTNER_JOIN_WAY_FINISH_TASK == stConPair._iKey)//完成特定任务
        {
            if (CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskFinished(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                stAns.add_append_join_type(stConPair._iValue);
            }
        }
    }

    return 0;
}

int CPartnerMgr::PartnerGetOneAct(CPartnerActData& stActData,
        CPartnerUnit& stPartnerUnit, MsgAnsActPartner& stMsgActPartner,
        CPlayerOnlineData& stPlayerOnline, CPlayerDetailInfo& stPlayerDetail,
        CPlayerBaseInfo& stPlayerBase)
{
    int iRet = 0;
    int iFavor = 0;
    int iIndex = 0;
    unsigned int uiLevelUpExp = 0;

    iIndex = FindPartnerCfg(stPartnerUnit._shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(
                (unsigned char)stActData._shLevel, uiLevelUpExp);
    if (iRet != 0)
    {
        CT_WARNING(("get level up exp error, level %d", stActData._shLevel));
    }

    stMsgActPartner.set_res_id(stPartnerUnit._shResID);
    stMsgActPartner.set_favor(0);
    iRet = CalcPartnerFavor(stPartnerUnit._shResID, stActData._iFavor, iFavor);
    if (0 == iRet)
    {
        stMsgActPartner.set_favor(iFavor);
    }

    MsgObjBase* pstObjBase = stMsgActPartner.mutable_base_info();
    pstObjBase->set_sex((stCfgData._bIsMan ? 1 : 0));
    pstObjBase->set_career(stCfgData._chCareer);
    pstObjBase->set_level(stActData._shLevel);
    pstObjBase->set_level_up_exp((int)uiLevelUpExp);
    pstObjBase->set_now_exp((int)(stActData._i64Exp & 0x7FFFFFFF));

    //技能ID列表
#if 0
    //拷贝技能信息给前端 由前端判断技能系统开关来决定是否显示技能
    if (CMainCtrl::m_pstMain->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_37,
            stPlayerBase, stPlayerOnline))
    {
        MsgObjSkill* pstObjSkill = pstObjBase->mutable_skill_info();
        pstObjSkill->set_activate_skill((int)stPartnerUnit._stMagicSkill.GetID());
        pstObjSkill->add_skill_list((int)stPartnerUnit._stNormalSkill.GetID());
        pstObjSkill->add_skill_list((int)stPartnerUnit._stMagicSkill.GetID());
    }
#else
    MsgObjSkill* pstObjSkill = pstObjBase->mutable_skill_info();
    pstObjSkill->set_activate_skill((int)stPartnerUnit._stMagicSkill.GetID());
    pstObjSkill->add_skill_list((int)stPartnerUnit._stNormalSkill.GetID());
    pstObjSkill->add_skill_list((int)stPartnerUnit._stMagicSkill.GetID());
#endif

    stMsgActPartner.set_special_id(0);//byronwei_tmp
    stMsgActPartner.set_lock_id(0);//byronwei_tmp

    CMainCtrl::m_pstMain->m_stRoleMgr.CopyBaseAttr(stPartnerUnit._stAttr, *(pstObjBase->mutable_attrs()));

    CMainCtrl::m_pstMain->m_stRoleMgr.CopyExtAttr(stPartnerUnit._stAttr, *(pstObjBase->mutable_fight_attrs()));

    //伙伴战斗力
    pstObjBase->set_obj_fighting(stPartnerUnit.GetFighting());

    T_EQUIP_DATA astEquipList;
    stActData._stEquip.GetEquipList(astEquipList);
    for (int i = 0; i < astEquipList.Size(); ++i)
    {        
        MsgGridItemInfo* pstEquip = stMsgActPartner.add_equips();
        CMainCtrl::m_pstMain->m_stEquipMgr.GetEquipInfo (stPlayerOnline._uiGID, astEquipList[i], *pstEquip); 
    }

    //卡片
    PartnerGetActCard(stMsgActPartner, stPlayerOnline, stPlayerDetail, stPartnerUnit);

    //秘宝 只返回个体身上携带的秘宝单元
    CMainCtrl::m_pstMain->m_stTreasureMgr.GetObjBaseTreasure(stPlayerDetail,
        *(pstObjBase), GAME_OBJ_TYPE_PARTNER,
        (unsigned int)stPartnerUnit._shResID);

    //是否在阵型上
    if (CMainCtrl::m_pstMain->m_stMatrixMgr.PartnerInMainMatrix(
            stPlayerDetail, stPartnerUnit._shResID))
    {
        stMsgActPartner.set_in_matrix(1);
    }
    else
    {
        stMsgActPartner.set_in_matrix(0);
    }

    return 0;
}

int CPartnerMgr::PartnerGetOneAct(CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfo& stPlayerDetail, CPlayerBaseInfo& stPlayerBase,
        MsgAnsActPartner& stMsgActPartner, short shResID)
{
    int iIndex = 0;

    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        CT_WARNING(("partner(%d) not in act list",shResID));
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

    iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex < 0)
    {
        CT_WARNING(("partner(%d) not in act list",shResID));
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

    return PartnerGetOneAct(stActData, stPartnerUnit, stMsgActPartner,
        stPlayerOnline, stPlayerDetail, stPlayerBase);

}

int CPartnerMgr::PartnerGetAct(CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfo& stPlayerDetail, CPlayerBaseInfo& stPlayerBase,
        MsgAnsPartner& stAns, short shResID)
{
    int iRet = 0;
    
    PartnerGetJoinWay(stPlayerBase, stPlayerOnline, stAns);

    iRet = PartnerGetAct(stPlayerOnline, stPlayerDetail, stPlayerBase,
        *(stAns.mutable_act_partner()), shResID);
    CT_RETURN(iRet);

    return 0;
}

int CPartnerMgr::PartnerGetAct(CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfo& stPlayerDetail, CPlayerBaseInfo& stPlayerBase,
        ::google::protobuf::RepeatedPtrField<MsgAnsActPartner>& stActPartners,
        short shResID)
{
    int iRet = 0;
    int iIndex = 0;

    if (shResID > 0)
    {
        iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
        if (iIndex < 0)
        {
            CT_WARNING(("partner(%d) not in act list",shResID));
            return ERROR_PARTNER_NOT_IN_ACT;
        }
        CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

        iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
        if (iIndex < 0)
        {
            CT_WARNING(("partner(%d) not in act list",shResID));
            return ERROR_PARTNER_NOT_IN_ACT;
        }
        CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

        return PartnerGetOneAct(stActData, stPartnerUnit,
            *(stActPartners.Add()), stPlayerOnline, stPlayerDetail,
            stPlayerBase);
    }

    for (int i = 0; i < stPlayerOnline._stUserPartner._astOnlineData.Size(); ++i)
    {
        CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner._astOnlineData[i];
        iIndex = stPlayerDetail._stUserPartner.FindActData(stPartnerUnit._shResID);
        if (iIndex < 0)
        {
            CT_WARNING(("partner(%d) not in act list",shResID));
            return ERROR_PARTNER_NOT_IN_ACT;
        }
        CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);
        iRet = PartnerGetOneAct(stActData, stPartnerUnit,
            *(stActPartners.Add()), stPlayerOnline, stPlayerDetail,
            stPlayerBase);
        CT_RETURN(iRet);
    }

    return 0;
}

int CPartnerMgr::PartnerGetOneList(CPartnerListData& stPartnerList,
        MsgAnsListPartner& stMsgListPartner)
{
    int iRet = 0;
    int iFavor = 0;
    int iIndex = 0;
    unsigned int uiLevelUpExp = 0;

    iIndex = FindPartnerCfg(stPartnerList._shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(
        (unsigned char)stPartnerList._shLevel, uiLevelUpExp);
    if (iRet != 0)
    {
        CT_WARNING(("get level up exp error, level %d",stPartnerList._shLevel));
    }

	CPlayerAttr	stPartnerAttr;//定义时初始化
    iRet = CMainCtrl::m_pstMain->m_stDrugMgr.GetDrugTotalAttr(
        stPartnerList._stDrugData, stPartnerAttr);
    if (iRet)
    {
        CT_ERROR(("%d, %d", stPartnerList._shResID, iRet));
    }

    CalcExtAttr(stCfgData, stPartnerAttr, stPartnerList._shLevel, true);

    stMsgListPartner.set_res_id(stPartnerList._shResID);
    stMsgListPartner.set_favor(0);
    iRet = CalcPartnerFavor(stPartnerList._shResID, stPartnerList._iFavor,
        iFavor);
    if (0 == iRet)
    {
        stMsgListPartner.set_favor(iFavor);
    }

    MsgObjBase* pstObjBase = stMsgListPartner.mutable_base_info();
    pstObjBase->set_sex((stCfgData._bIsMan ? 1 : 0));
    pstObjBase->set_career(stCfgData._chCareer);
    pstObjBase->set_level(stPartnerList._shLevel);
    pstObjBase->set_level_up_exp((int)uiLevelUpExp);
    pstObjBase->set_now_exp((int)(stPartnerList._i64Exp));

    MsgObjSkill* pstObjSkill = pstObjBase->mutable_skill_info();
    if (stCfgData._uiNormalSkiID > 0)
    {
        pstObjSkill->add_skill_list((int)stCfgData._uiNormalSkiID);
    }

    //技能ID列表
    if (stCfgData._uiMagicSkiID > 0)
    {
        pstObjSkill->set_activate_skill((int)stCfgData._uiMagicSkiID);
        pstObjSkill->add_skill_list((int)stCfgData._uiMagicSkiID);
    }

    CMainCtrl::m_pstMain->m_stRoleMgr.CopyBaseAttr(stPartnerAttr,
        *(pstObjBase->mutable_attrs()));

    CMainCtrl::m_pstMain->m_stRoleMgr.CopyExtAttr(stPartnerAttr,
        *(pstObjBase->mutable_fight_attrs()));

    pstObjBase->set_obj_fighting(0);//离队伙伴暂时不计算战斗力

    return 0;
}

int CPartnerMgr::PartnerGetList(CUnactPartnerInfo& stUnactPartnerInfo,
        ::google::protobuf::RepeatedPtrField<MsgAnsListPartner>& stListPartners,
        short shResID)
{
    int iRet = 0;
    int iIndex = 0;

    if (shResID > 0)
    {
        iIndex = stUnactPartnerInfo.FindListData(shResID);
        if (iIndex < 0)
        {
            CT_WARNING(("partner(%d) not in list",shResID));
            return ERROR_PARTNER_NOT_IN_LIST;
        }
        CPartnerListData& stPartnerList =
            stUnactPartnerInfo.GetPartnerListData(iIndex);

        return PartnerGetOneList(stPartnerList, *(stListPartners.Add()));
    }

    for (int i = 0; i < stUnactPartnerInfo._astListData.Size(); ++i)
    {
        CPartnerListData& stPartnerList = stUnactPartnerInfo._astListData[i];
        iRet = PartnerGetOneList(stPartnerList, *(stListPartners.Add()));
        CT_RETURN(iRet);
    }

    return 0;
}

//此Notify接口限定内部使用 如果确保base detail online unact数据都能取到 可以调用
int CPartnerMgr::NotifyPartner(unsigned int uiGID, int iNotifyMask)
{
    int iRet = 0;
    int iIndex = 0;

    if (iNotifyMask & PARTNER_NOTIFY_ACT)
    {
        iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("no base data user(%u)", uiGID));
            return RET_SYSTEM_FAIL;
        }
        CPlayerBaseInfo& stPlayerBase = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

        iIndex = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("no detail data user(%u)", uiGID));
            return RET_SYSTEM_FAIL;
        }
        CPlayerDetailInfo& stPlayerDetail = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash[iIndex];

        iIndex = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("no online data user(%u)", uiGID));
            return RET_SYSTEM_FAIL;
        }
        CPlayerOnlineData& stPlayerOnline = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash[iIndex];

        MsgAnsPartner stMsgPartner;
        stMsgPartner.set_gid((int)uiGID);
        stMsgPartner.set_sub_type(CMD_PARTNER_SUB_ACT);

    	iRet = PartnerGetAct(stPlayerOnline, stPlayerDetail, stPlayerBase, stMsgPartner);
        if (!iRet)
        {
            CMainCtrl::m_pstMain->NotifyOnlineUser(uiGID, ID_MAIN_PARTNER, stMsgPartner, false);
        }
    }

    if (iNotifyMask & PARTNER_NOTIFY_LIST)
    {
        iIndex = CMainCtrl::m_pstMain->m_stUnactPartnerInfoHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("no unact partner data user(%u)", uiGID));
            return RET_SYSTEM_FAIL;
        }
        CUnactPartnerInfo& stUnactPartnerInfo = CMainCtrl::m_pstMain->m_stUnactPartnerInfoHash[iIndex];

        MsgAnsPartner stMsgPartner;
        stMsgPartner.set_gid((int)uiGID);
        stMsgPartner.set_sub_type(CMD_PARTNER_SUB_LIST);

    	iRet = PartnerGetList(stUnactPartnerInfo, *(stMsgPartner.mutable_list_partner()));
        if (!iRet)
        {
            CMainCtrl::m_pstMain->NotifyOnlineUser(uiGID, ID_MAIN_PARTNER, stMsgPartner, false);
        }
    }

    return 0;
}

short CPartnerMgr::GetFirstPayPartner()
{
    if (_shFirstPayPartner <= 0)
    {
        for (int i = 0; i < _stPartnerCfg.GetPartnerCfgSize(); ++i)
        {
            CPartnerCfgData& stCfgData = _stPartnerCfg.GetConfig(i);
            if (PARTNER_JOIN_WAY_FIRST_PAY == stCfgData._iJoinWay)
            {
                SetFirstPayPartner(stCfgData.GetResID());
                break;
            }
        }
    }
    
    return _shFirstPayPartner;
}

int CPartnerMgr::PartnerJoinFirstPay(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    int iRet = 0;
    short shPartnerID = GetFirstPayPartner();

    MsgAnsPartner stAns;
    stAns.set_gid(stPlayerBase._uiGID);
    stAns.set_sub_type(CMD_PARTNER_SUB_JOIN);

    iRet = PartnerJoin(shPartnerID, PARTNER_JOIN_TYPE_SYSTEM, stPlayerBase,
        stPlayerDetail, stUnactPartnerInfo, stPlayerOnline, stPlayerDetailEx1,
        stAns);
    if (iRet)
    {
        CT_ERROR(("role(%u) join first pay partner(%d) error(%d)",
            stPlayerBase._uiGID,shPartnerID,iRet));
        return iRet;
    }

    return CMainCtrl::m_pstMain->NotifyOnlineUser(stPlayerBase._uiGID,
        ID_MAIN_PARTNER, stAns, false);
}

int CPartnerMgr::PartnerJoinUseItem(short shResID,
        CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    int iRet = 0;

    MsgAnsPartner stAns;
    stAns.set_gid(stPlayerBase._uiGID);
    stAns.set_sub_type(CMD_PARTNER_SUB_JOIN);

    iRet = PartnerJoin(shResID, PARTNER_JOIN_TYPE_SYSTEM, stPlayerBase,
        stPlayerDetail, stUnactPartnerInfo, stPlayerOnline, stPlayerDetailEx1,
        stAns);
    if (iRet)
    {
        CT_ERROR(("role(%u) use item partner(%d) error(%d)",
            stPlayerBase._uiGID, shResID, iRet));
        return iRet;
    }

    return CMainCtrl::m_pstMain->NotifyOnlineUser(stPlayerBase._uiGID,
        ID_MAIN_PARTNER, stAns, false);
}

bool CPartnerMgr::IsRoleGetPartner(short shResID,
        CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo)
{
    int iIndex = 0;
    iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex >= 0)
    {
        return true;
    }

    iIndex = stUnactPartnerInfo.FindListData(shResID);
    if (iIndex >= 0)
    {
        return true;
    }

    return false;
}

int CPartnerMgr::CheckPartnerJoin(short shResID, int iJoinType,
        CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline)
{
    if (!IsValidJoinType(iJoinType))
    {
        return ERROR_PARTNER_JOIN_TYPE_UNKNOW;
    }

    int iRet = 0;
    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    //是否已招满
    if (stPlayerOnline._stUserPartner.IsFullOnlinePartner())
    {
        return ERROR_PARTNER_ACT_FULL;
    }

    //是否已经激活
    iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex >= 0)
    {
        return ERROR_PARTNER_ACT_ALREADY;
    }

    //是否已经招募
    iIndex = stUnactPartnerInfo.FindListData(shResID);
    if (iIndex >= 0)
    {
        return ERROR_PARTNER_JOIN_ALREADY;
    }

    //银币
    if (stCfgData._iSilver < 0)
    {
        return ERROR_PARTNER_ERROR_CFG;
    }
    iRet = CPlayerBaseInfo::CheckInt64Value(stPlayerBase._i64Silver,
        0 - stCfgData._iSilver);
    if (iRet)
    {
        return ERROR_SILVER_LESS;
    }

    //声望
    if (stCfgData._iRepu < 0)
    {
        return ERROR_PARTNER_ERROR_CFG;
    }
    if (stPlayerDetail._iReputation < stCfgData._iRepu)
    {
        return ERROR_PARTNER_REPU_LESS;
    }

    //额外招募条件检查
    if (stCfgData._iJoinWay > 0)
    {
        //如果是首充伙伴方式必须是系统招募类型以此限制玩家自行招募首充伙伴
        if (PARTNER_JOIN_WAY_FIRST_PAY == stCfgData._iJoinWay &&
            PARTNER_JOIN_TYPE_SYSTEM != iJoinType)
        {
            return ERROR_PARTNER_FIRST_PAY_BY_SYS;
        }

        //能否领取首充奖励伙伴
        if (PARTNER_JOIN_WAY_FIRST_PAY == stCfgData._iJoinWay &&
            stPlayerBase._stVipData._ucCanGetFirstPayBonus <= 0)
        {
            CT_WARNING(("role(%u) first pay bonus(%d) join partner(%d) error",
                stPlayerBase._uiGID,
                stPlayerBase._stVipData._ucCanGetFirstPayBonus,shResID));
            return ERROR_PARTNER_JOIN_WAY_NO_ENOUGH;
        }

        CTaskID stTaskID;
        CMainCtrl::m_pstMain->m_stTaskMgr.GetTaskIDStruct(stCfgData._iJoinArgu,
            stTaskID);

        if (PARTNER_JOIN_WAY_RECEIVE_OR_FINISH_TASK == stCfgData._iJoinWay &&
            stCfgData._iJoinArgu > 0)//已接取或完成特定任务
        {
            if (!CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskAccepted(
                    stPlayerOnline._stUserTask, stTaskID) &&
                !CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskFinished(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                return ERROR_PARTNER_ACCEPT_OR_FINISH_TASK;
            }
        }

        if (PARTNER_JOIN_WAY_RECEIVE_TASK == stCfgData._iJoinWay &&
            stCfgData._iJoinArgu > 0)//已接取特定任务
        {
            if (!CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskAccepted(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                return ERROR_PARTNER_ACCEPT_GIVEN_TASK;
            }
        }

        if (PARTNER_JOIN_WAY_FINISH_TASK == stCfgData._iJoinWay &&
            stCfgData._iJoinArgu > 0)//完成特定任务
        {
            if (!CMainCtrl::m_pstMain->m_stTaskMgr.IsTaskFinished(
                    stPlayerOnline._stUserTask, stTaskID))
            {
                return ERROR_PARTNER_FINISH_GIVEN_TASK;
            }
        }

        //如果是物品伙伴必须是系统招募类型以此限制玩家自行招募物品伙伴
        if (PARTNER_JOIN_WAY_USE_ITEM == stCfgData._iJoinWay &&
            PARTNER_JOIN_TYPE_SYSTEM != iJoinType)
        {
            return ERROR_PARTNER_USE_ITEM_BY_SYS;
        }
    }

    return 0;
}

int CPartnerMgr::PartnerJoin(short shResID, int iJoinType,
        CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsPartner& stAns)
{
    int iRet = 0;
    iRet = CheckPartnerJoin(shResID, iJoinType, stPlayerBase, stPlayerDetail,
        stUnactPartnerInfo, stPlayerOnline);
    CT_RETURN(iRet);

    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    CPartnerUnit stPartnerUnit;
    iRet = stPartnerUnit.InitByCfg(stCfgData);
    CT_RETURN(iRet);

    CPartnerActData stActData;//定义时初始化 需要将初始装备放入 故在这里定义
    stActData._shLevel = 1;

    //初始武器
    if (stCfgData._iWeaponID > 0)
    {
        unsigned int uiEquipID;
        iRet = CMainCtrl::m_pstMain->m_stEquipMgr.WearEquip(stPlayerDetail,
            stPlayerOnline._stUserEquip, stCfgData._iWeaponID,
            stCfgData._shResID, uiEquipID);
        CT_RETURN(iRet);

        CT_TRACE(("Partner(%d) Join add weapon(resid=%d equipid=%u)",
                    stCfgData._shResID,stCfgData._iWeaponID,uiEquipID));

        iRet = stActData._stEquip.SetEquip(uiEquipID, PARTNER_EQUIP_POS_WEAPON);
        CT_RETURN(iRet);
    }

    //扣除银币
    iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubSilver(stPlayerBase, stCfgData._iSilver, 0);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerDetail._uiGID, NOTIFY_USER_MONEY);

    iRet = stPlayerOnline._stUserPartner.AddPartner(stPartnerUnit);
    CT_RETURN(iRet);

    //必须实时保存到ActData
    iRet = stPartnerUnit.TransToActData(stActData);//注意装备已经提前放入
    CT_RETURN(iRet);

    int iNewActIndex = stPlayerDetail._stUserPartner._astActData.AddOneItem(stActData);
    if (iNewActIndex < 0)
    {
        CT_WARNING((""));
        return iNewActIndex;
    }

    //重新计算伙伴的属性加成
    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stNewPartnerUnit =
        stPlayerOnline._stUserPartner.GetPartner(iIndex);

    iRet = stNewPartnerUnit.ReCalcExtAttr(
        stPlayerDetail._stUserPartner._astActData[iNewActIndex],
        stPlayerBase, stPlayerDetail, stPlayerOnline, stPlayerDetailEx1,
        false, false);
    CT_RETURN(iRet);

    iRet = NotifyPartner(stPlayerDetail._uiGID, PARTNER_NOTIFY_ACT);
    CT_RETURN(iRet);

    stAns.set_partner_id(shResID);

    return 0;
}

int CPartnerMgr::PartnerSign(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsPartner& stAns)
{
    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    //是否在激活在线列表
    iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

    //好感度 由契约战斗次数转换
    if (stActData._iFavor >= PARTNER_FAVOR_FOR_LOCK)
    {
        return ERROR_PARTNER_SIGN_ALREADY;
    }
    if (stActData._iFavor < stCfgData._iSignBattle)
    {
        return ERROR_PARTNER_SIGN_BATTLE_LESS;
    }

    //银币
    if (stCfgData._iSignSilver < 0)
    {
        return ERROR_PARTNER_ERROR_CFG;
    }
    int iRet = CPlayerBaseInfo::CheckInt64Value(stPlayerBase._i64Silver,
            0 - stCfgData._iSignSilver);
    if (iRet)
    {
        return ERROR_SILVER_LESS;
    }

    //扣除银币
    iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubSilver(stPlayerBase, stCfgData._iSignSilver, 0);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerDetail._uiGID, NOTIFY_USER_MONEY);

    stActData._iFavor = PARTNER_FAVOR_FOR_LOCK;

    //重新计算二级属性
    iRet = stPartnerUnit.ReCalcExtAttr(stActData, stPlayerBase, stPlayerDetail,
        stPlayerOnline, stPlayerDetailEx1, false, false);
    CT_RETURN(iRet);

    iRet = NotifyPartner(stPlayerDetail._uiGID, PARTNER_NOTIFY_ACT);
    CT_RETURN(iRet);

    stAns.set_partner_id(shResID);

    return 0;
}

int CPartnerMgr::PartnerLock(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsPartner& stAns)
{
    int iRet = 0;
    int iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    //是否在激活在线列表
    iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

    //信赖度 由锁链战斗次数转换
    if (stActData._iFavor < PARTNER_FAVOR_FOR_LOCK)
    {
        return ERROR_PARTNER_NOT_SIGN;
    }
    if (stActData._iFavor >= PARTNER_FAVOR_FOR_POWER)
    {
        return ERROR_PARTNER_LOCK_ALREADY;
    }
    if (stActData._iFavor - PARTNER_FAVOR_FOR_LOCK < stCfgData._iLockBattle)
    {
        return ERROR_PARTNER_LOCK_BATTLE_LESS;
    }

#if 0
    //锁链效果
    if (stCfgData._iLockEffect > 0)
    {
        iIndex = CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillEffCfg(stCfgData._iLockEffect);
        if (iIndex >= 0)
        {
            CSkillEffCfgData& stLockSkillEffCfg = CMainCtrl::m_pstMain->m_stSkillMgr.GetSkillEffCfg(iIndex);
            iRet = stPartnerUnit._stLockSkillEff.InitByEffCfg(stLockSkillEffCfg);
            CT_RETURN(iRet);

            stActData._iLockID = stCfgData._iLockEffect;
        }
    }
#endif

    stActData._iFavor = PARTNER_FAVOR_FOR_POWER;

    //重新计算二级属性
    iRet = stPartnerUnit.ReCalcExtAttr(stActData, stPlayerBase, stPlayerDetail,
        stPlayerOnline, stPlayerDetailEx1, false, false);
    CT_RETURN(iRet);

    iRet = NotifyPartner(stPlayerDetail._uiGID, PARTNER_NOTIFY_ACT);
    CT_RETURN(iRet);

    stAns.set_partner_id(shResID);

    return 0;
}

int CPartnerMgr::PartnerLeave(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline, MsgAnsPartner& stAns)
{
    int iRet = 0;
    //是否在激活在线列表
    int iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

    //装备
    if (!stActData._stEquip.IsAllClear())
    {
        return ERROR_PARTNER_EQUIP_NOT_CLEAR;
    }

    //卡片
    if (stActData._stPlayerWareCard.HasCard())
    {
        return ERROR_PARTNER_EQUIP_NOT_CLEAR;
    }

    //命运旋窝
    if (stActData._stCardVortex.HasVortex())
    {
        return ERROR_PARTNER_EQUIP_NOT_CLEAR;
    }

    if (stUnactPartnerInfo.IsFullListData())
    {
        //历史列表已满 系统错误
        return ERROR_PARTNER_LIST_FULL;
    }

    //秘宝
    iRet = CMainCtrl::m_pstMain->m_stTreasureMgr.TakeOffPartnerTreasure(shResID, stPlayerBase, stPlayerDetail, stPlayerOnline);
    CT_RETURN(iRet);

    CPartnerListData stListData;
    iRet = stPartnerUnit.TransToListData(stActData, stListData);
    CT_RETURN(iRet);

    //加到历史列表
    iRet = stUnactPartnerInfo._astListData.AddOneItem(stListData);
    if (iRet < 0)
    {
        stUnactPartnerInfo.DelListData(shResID);
        return ERROR_PARTNER_LIST_FULL;
    }

    //删除激活在线列表
    iRet = stPlayerOnline._stUserPartner.DelPartner(shResID);
    if (0 != iRet)
    {
        stUnactPartnerInfo.DelListData(shResID);
        return ERROR_PARTNER_LIST_FULL;
    }

    //删除激活DB列表
    iRet = stPlayerDetail._stUserPartner.DelActData(shResID);
    CT_RETURN(iRet);

    //将伙伴从角色阵形中删除 伙伴这边暂时不记录是否加入阵形的标识
    iRet = CMainCtrl::m_pstMain->m_stMatrixMgr.DelAllPartner(stPlayerBase, stPlayerDetail, stPlayerOnline, shResID);
    CT_RETURN(iRet);

    iRet = NotifyPartner(stPlayerDetail._uiGID, PARTNER_NOTIFY_ACT | PARTNER_NOTIFY_LIST);
    CT_RETURN(iRet);

    stAns.set_partner_id(shResID);

    return 0;
}

int CPartnerMgr::PartnerRecall(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgAnsPartner& stAns)
{
    //是否在历史列表
    int iIndex = stUnactPartnerInfo.FindListData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_LIST;
    }
    CPartnerListData& stListData = stUnactPartnerInfo.GetPartnerListData(iIndex);

    if (stPlayerOnline._stUserPartner.IsFullOnlinePartner())
    {
        //激活在线列表已满
        return ERROR_PARTNER_ACT_FULL;
    }

    iIndex = FindPartnerCfg(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_EMPTY_CFG;
    }
    CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

    CPartnerUnit stPartnerUnit;
    int iRet = stPartnerUnit.InitByListData(stCfgData, stListData);
    CT_RETURN(iRet);

    CPartnerListData stListDataBak = stListData;//这个是拷贝 因为要先删除历史

    //加到激活在线列表
    iRet = stPlayerOnline._stUserPartner.AddPartner(stPartnerUnit);
    if (0 != iRet)
    {
        stPlayerOnline._stUserPartner.DelPartner(shResID);
        return ERROR_PARTNER_ACT_FULL;
    }

    //删除历史列表
    iRet = stUnactPartnerInfo.DelListData(shResID);
    if (0 != iRet)
    {
        stPlayerOnline._stUserPartner.DelPartner(shResID);
        return ERROR_PARTNER_ACT_FULL;
    }

    //必须实时保存到ActData
    CPartnerActData stActData;
    iRet = stPartnerUnit.TransToActData(stListDataBak, stActData);
    CT_RETURN(iRet);

    int iNewActIndex = stPlayerDetail._stUserPartner._astActData.AddOneItem(stActData);
    if (iNewActIndex < 0)
    {
        CT_WARNING((""));
        return iNewActIndex;
    }

    //重新计算伙伴的属性加成
    iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerUnit& stNewPartnerUnit = stPlayerOnline._stUserPartner.GetPartner(iIndex);

    iRet = stNewPartnerUnit.ReCalcExtAttr(
        stPlayerDetail._stUserPartner._astActData[iNewActIndex], stPlayerBase,
        stPlayerDetail, stPlayerOnline, stPlayerDetailEx1, false, false);
    CT_RETURN(iRet);

    iRet = NotifyPartner(stPlayerDetail._uiGID, PARTNER_NOTIFY_ACT | PARTNER_NOTIFY_LIST);
    CT_RETURN(iRet);

    stAns.set_partner_id(shResID);

    return 0;
}

int CPartnerMgr::PartnerChkActStat(short shResID, CPlayerOnlineData& stPlayerOnline)
{
    int iIndex = stPlayerOnline._stUserPartner.FindPartner(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }

    return 0;
}

int CPartnerMgr::PartnerChkEquipStat(short shResID, CPlayerDetailInfo& stPlayerDetail,
                   CPlayerOnlineData& stPlayerOnline, unsigned int uiEquipID, int iPos)
{
    int iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_ACT;
    }
    CPartnerActData& stActData = stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

    unsigned int uiOldEquipID = 0;
    int iRet = stActData._stEquip.GetEquip(uiOldEquipID, iPos);
    CT_RETURN(iRet);

    if (uiOldEquipID != uiEquipID)
    {
        if (0 == uiEquipID)
        {
            return ERROR_EQUIP_POS_NOT_CLEAR;
        }
        else
        {
            return ERROR_EQUIP_ID_NOT_MATCH;
        }
    }

    return 0;
}

int CPartnerMgr::PartnerWearEquip(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        unsigned int uiEquipID, int iPos)
{
    if (uiEquipID == 0)
    {
        return ERROR_EQUIP_UNKNOW_ID;
    }

    //接口内部校验
    int iRet = stPlayerDetail._stUserPartner.WearEquip(shResID, uiEquipID, iPos);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID,
        NOTIFY_PARTNER_ATTR, shResID);

    return 0;
}

int CPartnerMgr::PartnerTakeOffEquip(short shResID,
        CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
        CPlayerOnlineData& stPlayerOnline, unsigned int uiEquipID, int iPos)
{
    if (uiEquipID == 0)
    {
        return ERROR_EQUIP_UNKNOW_ID;
    }

    //接口内部校验
    int iRet = stPlayerDetail._stUserPartner.TakeOffEquip(shResID, uiEquipID, iPos);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID,
        NOTIFY_PARTNER_ATTR, shResID);

    return 0;
}

int CPartnerMgr::GMDealPartner(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CUnactPartnerInfo& stUnactPartnerInfo,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, MsgReqGMPlayer& stReq,
        MsgAnsGMPlayer& stAns)
{
    int iRet = 0;
    int iIndex = 0;
    int iAddExp = 0;
    bool bIsUnAct = false;
    CTSizeString<MAX_BATTLE_NAME_BUFF> szNameStr;
    switch (stReq.sub_type())
    {
    case ID_GM_PLAYER_SUB_ACT_PARTNER:
        {
            szNameStr.Cat("激活伙伴总数:%d",
                          stPlayerDetail._stUserPartner._astActData.Size());

            for (int i = 0; i <
                    stPlayerDetail._stUserPartner._astActData.Size(); ++i)
            {
                CPartnerActData& stActData =
                    stPlayerDetail._stUserPartner._astActData[i];
                iIndex = FindPartnerCfg(stActData._shResID);
                if (iIndex < 0)
                {
                    continue;
                }
                CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

                szNameStr.Cat("\nID:%d ",stActData._shResID);
                szNameStr.Cat("性别:%d ",stCfgData._bIsMan);
                szNameStr.Cat("职业:%d ",stCfgData._chCareer);
                szNameStr.Cat("等级:%d ",stActData._shLevel);
                szNameStr.Cat("经验:%lld ",stActData._i64Exp);
                szNameStr.Cat("好感度:%d ",stActData._iFavor);
                szNameStr.Cat("普通技能:%u ",stCfgData._uiNormalSkiID);
                szNameStr.Cat("幻化技能:%u ",stCfgData._uiMagicSkiID);
                szNameStr.Cat("特殊能力:%d ",stCfgData._iSpeEffect);
                szNameStr.Cat("锁链能力:%d",stCfgData._iLockEffect);
            }
            
            stAns.set_name(szNameStr.Get());
        }
        break;
    case ID_GM_PLAYER_SUB_LIST_PARTNER:
        {
            szNameStr.Cat("离队伙伴总数:%d",
                          stUnactPartnerInfo._astListData.Size());
        
            for (int i = 0; i < stUnactPartnerInfo._astListData.Size(); ++i)
            {
                CPartnerListData& stListData =
                    stUnactPartnerInfo._astListData[i];
                iIndex = FindPartnerCfg(stListData._shResID);
                if (iIndex < 0)
                {
                    continue;
                }
                CPartnerCfgData& stCfgData = GetPartnerCfg(iIndex);

                szNameStr.Cat("\nID:%d ",stListData._shResID);
                szNameStr.Cat("性别:%d ",stCfgData._bIsMan);
                szNameStr.Cat("职业:%d ",stCfgData._chCareer);
                szNameStr.Cat("等级:%d ",stListData._shLevel);
                szNameStr.Cat("经验:%lld ",stListData._i64Exp);
                szNameStr.Cat("好感度:%d",stListData._iFavor);
                szNameStr.Cat("普通技能:%u ",stCfgData._uiNormalSkiID);
                szNameStr.Cat("幻化技能:%u ",stCfgData._uiMagicSkiID);
                szNameStr.Cat("特殊能力:%d ",stCfgData._iSpeEffect);
                szNameStr.Cat("锁链能力:%d",stCfgData._iLockEffect);
            }
            
            stAns.set_name(szNameStr.Get());
        }
        break;
    case ID_GM_PLAYER_SUB_CHG_PARTNER_FAVOR:
        if (stReq.datas_size() >= 2)
        {
            iIndex = stPlayerDetail._stUserPartner.FindActData(
                (short)stReq.datas(0));
            if (iIndex >= 0)
            {
                CPartnerActData& stActData =
                     stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);
                stActData._iFavor += (int)stReq.datas(1);
                if (stActData._iFavor < 0)
                {
                    stActData._iFavor = 0;
                }
            }
        }
        break;
    case ID_GM_PLAYER_SUB_CHG_PARTNER_LEVEL://修改伙伴等级
    case ID_GM_PLAYER_SUB_CHG_PARTNER_EXP://修改伙伴经验
        if (stReq.datas_size() >= 2 && stReq.datas(0) > 0 && stReq.datas(1) > 0)
        {
            short shLevel = 0;
            short shResID = (short)stReq.datas(0);
            unsigned int uiLevelExp = 0;
            iIndex = stPlayerDetail._stUserPartner.FindActData(shResID);
            if (iIndex >= 0)
            {
                CPartnerActData& stActData =
                    stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);
                shLevel = stActData._shLevel;
            }
            else
            {
                iIndex = stUnactPartnerInfo.FindListData(shResID);
                if (iIndex >= 0)
                {
                    bIsUnAct = true;
                    CPartnerListData& stListData =
                        stUnactPartnerInfo.GetPartnerListData(iIndex);
    	            shLevel = stListData._shLevel;
                }
            }

            if (shLevel <= 0)
            {
                return 0;
            }

            if (stReq.sub_type() == ID_GM_PLAYER_SUB_CHG_PARTNER_LEVEL)
            {
                for (int i = shLevel; i < stReq.datas(1) &&
                        i < MAX_PARTNER_LEVEL; ++i)
                {
                    iRet =
                        CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(
                            (unsigned char)i, uiLevelExp);
                    CT_RETURN(iRet);
                    iAddExp += (int)uiLevelExp;
                }
            }
            else
            {
                iAddExp += (int)stReq.datas(1);
            }

            if (iAddExp <= 0)
            {
                return 0;
            }

            if (bIsUnAct)
            {
                iRet = UnactPartnerAddExp(shResID, iAddExp, stPlayerBase,
                    stUnactPartnerInfo);
                CT_RETURN(iRet);
            }
            else
            {
                iRet = PartnerAddExp(shResID, iAddExp, stPlayerBase,
                    stPlayerDetail, stPlayerOnline, stPlayerDetailEx1);
                CT_RETURN(iRet);
            }
        }
        break;
    case ID_GM_PLAYER_SUB_PARTNER_ATTR://查看伙伴属性
        if (stReq.datas_size() >= 1 && stReq.datas(0) > 0)
        {
            iIndex = stPlayerOnline._stUserPartner.FindPartner(
                (short)stReq.datas(0));
            if (iIndex >= 0)
            {
                CPartnerUnit& stPartnerUnit =
                    stPlayerOnline._stUserPartner.GetPartner(iIndex);

                if (stReq.datas_size() >= 3)
                {
                    int iType = stReq.datas(1);
                    int iVal = stReq.datas(2);
                
                    if (-1 == iType)
                    {
                        for (int i = EXT_ATTR_MIM; i <= EXT_ATTR_MAX; ++i)
                        {
                            stPartnerUnit._stAttr.SetAttr(i, CT_MAX(1, iVal));
                        }
                    }
                    else
                    {
                        if (iType >= EXT_ATTR_MIM && iType <= EXT_ATTR_MAX &&
                            iVal >= 0)
                        {
                            stPartnerUnit._stAttr.SetAttr(iType, iVal);
                        }
                    }
                }

                CMainCtrl::m_pstMain->m_stRoleMgr.GMCopyRoleAttr(
                    stPartnerUnit._stAttr, stAns);
            }
        }
        break;
    default:
        return ERROR_MAIN_SUB_CMD;
    }

    return 0;
}

int CPartnerMgr::PartnerUpLevel(short shResID, CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    return stPlayerOnline._stUserPartner.UpLevel(shResID, 0, stPlayerBase,
        stPlayerDetail, stPlayerOnline, stPlayerDetailEx1);
}

int CPartnerMgr::PartnerAddExp(short shResID, int iAddExp,
        CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
        CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1)
{
    return stPlayerOnline._stUserPartner.AddExp(shResID, iAddExp, stPlayerBase,
         stPlayerDetail, stPlayerOnline, stPlayerDetailEx1);
}

int CPartnerMgr::UnactPartnerAddExp(short shResID, int iAddExp,
        CPlayerBaseInfo& stPlayerBase, CUnactPartnerInfo& stUnactPartnerInfo)
{
    if (iAddExp <= 0)
    {
        return 0;
    }

    int iIndex = stUnactPartnerInfo.FindListData(shResID);
    if (iIndex < 0)
    {
        return ERROR_PARTNER_NOT_IN_LIST;
    }
    CPartnerListData& stListData =
        stUnactPartnerInfo.GetPartnerListData(iIndex);

    return DealUpLevel(stListData._shLevel, stPlayerBase._shLevel, iAddExp,
        stListData._i64Exp);
}

int CPartnerMgr::DealUpLevel(short& shLevel, short shRoleLevel, int64 i64AddExp,
        int64& i64RoleExp)
{
    if (i64AddExp <= 0)
    {
        return 0;
    }

    //简单校验数值
    if (shLevel < 0 || i64RoleExp < 0)
    {
        return ERROR_PARTNER_DATA_VALID;
    }

    unsigned int uiLevelExp = 0;
    int64 i64LevelExp = 0;

    int iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(shLevel,
            uiLevelExp);
    CT_RETURN(iRet);

    i64LevelExp = (int64)(uiLevelExp);

    int64 i64Tmp = i64RoleExp + i64AddExp;

    while(i64Tmp >= i64LevelExp)
    {
        if (shLevel >= MAX_PARTNER_LEVEL)
        {
            break;//必须退出
        }
        else if (shLevel >= shRoleLevel)
        {
            i64Tmp = i64LevelExp;
            break;//必须退出
        }
        else
        {
            i64Tmp -= i64LevelExp;
            ++shLevel;
        }

        iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(shLevel,
            uiLevelExp);
        CT_RETURN(iRet);

        i64LevelExp = (int64)(uiLevelExp);
    };

    i64RoleExp = i64Tmp;
    if (shLevel >= OPEN_ROLE_LEVEL)
    {
        i64RoleExp = 0;
    }

    return 0;
}

